var GownFullMenu = Base.extend({
	ime: null,
	available: false,
	last_im: 0,
	escape_last: 0,

	items: [

	{ display: 'Toggle on/off IME', func: function(menu)
		{
			if(menu.ime.mainwin.shown) {
				menu.last_im = menu.ime.im_current;
				menu.ime.ToggleIME(false);
			}
			else {
				menu.ime.ToggleIME(true);
				menu.ime.SelectInputMethod(menu.last_im);
			}
		}
	},

	{ display: 'GownFull Blog', func: function(menu)
		{
			lib.openURL('http://gownfull.blogspot.com/');
		}
	}

	],
	constructor: function(ime)
	{
		this.ime = ime;
	},
	SelectItem: function(i)
	{
		var item = this.items[i];

		if(item) item.func(this);
	},
	ShowMenu: function()
	{
		var i;

		this.ime.ResetPreedit();
		for(i=0;i<9;i++) {
			if(i >= this.items.length) this.ime.SetCandidate(i+1,' ');
			else this.ime.SetCandidate(i+1,this.items[i].display);
		}
		this.ime.ShowCandidateListWindow(true);
		this.available = true;
	},
	HideMenu: function()
	{
		this.ime.ShowCandidateListWindow(false);
		this.available = false;
	},
	keydown_handler: function(obj,code)
	{
		return true;
	},
	keypress_handler: function(obj,code)
	{
		if(this.available) {
			if(49 <= code && code <= 59) { // 1-9
				this.SelectItem(code-49);
				this.HideMenu();
				return false;
			}
			else {
				this.HideMenu();
				return true;
			}
		}
		else {
			var now = lib.time();

			if(code == 27) {
				if(this.escape_last > 0 && now - this.escape_last < 500) {
					this.escape_last = 0;
					this.ShowMenu();
					return false;
				}
				else this.escape_last = now;
			}
			return true;
		}
	},
	keyup_handler: function(obj,code)
	{
		return true;
	}
});

var GownFull = Base.extend({
	constructor: function(builder)
	{
		var i;
		var x = this;

		this.builder = builder;
		this.handlers = builder.BuildObjectHandler();

		builder.BuildCSS();
		this.mainwin = builder.BuildMainWindow(function(v) { x.onSelectChange(v); });
		this.candwin = builder.BuildCandidateListWindow();
		builder.SetHandler(function(obj,key) { return x.keydown_handler(obj,key); },
				function(obj,key) { return x.keyup_handler(obj,key); },
				function(obj,key) { return x.keypress_handler(obj,key); });

		if(GownFull.instance) {
			Debug.trace(0,'GownFull: Error, more than one instance of GownFull created.');
		}
		GownFull.instance = this;

		this.menu = new GownFullMenu(this);

		builder.PostCreateGownFull();
	},

	mainwin: null,
	candwin: null,
	handlers: null,
	builder: null,

	preedit: '',
	im_array: [],
	im_current: 0,
	download_array: [],
	download_count: 0,
	modifiers: new GFList,
	menu: null,

	onSelectChange: function(value)
	{
		var im,i;

		if(value < 0) {
			// disable first
			if(this.im_current > 0) {
				im = this.im_array[this.im_current-1];
				im.onDeactive();
			}
			this.im_current = 0;
			this.ResetPreedit();
			// get url
			i = -value;
			i--;
			data = this.download_array[i];
			this.DownloadInputMethod(data.objname,value);
		}
		else {
			if(this.im_current > 0) {
				im = this.im_array[this.im_current-1];
				im.onDeactive();
			}
			this.im_current = value;
			Debug.trace(1,'GownFull: Select Input Method %d',value);
			this.ResetPreedit();
			if(this.im_current > 0) {
				im = this.im_array[this.im_current-1];
				im.onActive();
			}
		}
	},
	keydown_handler: function(obj,key)
	{
		var b;

		Debug.trace(4,'GownFull: keydown_handler key=%d',key);

		b = true;
		if(this.im_current > 0) {
			var im = this.im_array[this.im_current-1];
	
			b = im.keydown_handler(obj,key);
		}

		if(!this.menu.keydown_handler(obj,key)) b = false;
		
		return b;
	},
	keyup_handler: function(obj,key)
	{
		var b;

		Debug.trace(4,'GownFull: keyup_handler key=%d',key);

		b = true;

		if(this.im_current > 0) {
			var im = this.im_array[this.im_current-1];
	
			b = im.keyup_handler(obj,key);
		}
		if(!this.menu.keyup_handler(obj,key)) b = false;
		return b;
	},
	keypress_handler: function(obj,key)
	{
		var b;

		Debug.trace(4,'GownFull: keypress_handler key=%d',key);

		b = true;

		if(this.im_current > 0) {
			var im = this.im_array[this.im_current-1];

			b = im.keypress_handler(obj,key);
		}
		if(!this.menu.keypress_handler(obj,key)) b = false;
		return b;
	},
	RegisterInputMethod: function(im)
	{
		var i = this.im_array.length;
		this.im_array[i] = im;
		// add new select
		this.mainwin.AddSelectOption(im.IMName(),i+1,this.mainwin.TYPE_AVAILABLE);
		im.ime = this;
		Debug.trace(0,"GownFull: Register a Input Method \"%s\", id=%d",im.IMName(),i+1);
		return (i+1);
	},
	RegisterDownload: function(objname,name)
	{
		var i = this.download_array.length;
		this.download_array[i] = { name: name, objname: objname };
		// add new select
		this.mainwin.AddSelectOption(name,-i-1,this.mainwin.TYPE_DOWNLOAD);
		Debug.trace(0,"GownFull: Register an available Input Method (objname=\"%s\", name=\"%s\" id=%d)",objname,name,i+1);
		return (i+1);
	},
	DownloadInputMethod: function(objname,old_i)
	{
		var url;
		var data = {};

		url = lib.sprintf("%s?objname=%s",GownFullConfig.getim_url,objname);
		Debug.trace(0,"GownFull: Download Input Method %s",objname);
		
		this.SetPreeditText(lib.sprintf("Loading %s...",objname));

		data.objname = objname;
		data.old_i = old_i;
		this.download_count++;
		DownloadManager.NewDownload(url,
			function(userdata,serverdata) { 
				if(serverdata) {
					GownFull.instance.DownloadInputMethod2(serverdata,userdata.old_i);
					GownFull.instance.ResetPreedit();
				}
				else {
					GownFull.instance.SetPreeditText(userdata.objname+' does not exist.');
				}
				GownFull.instance.download_count--;
			},
		data);
		return true;
	},
	DownloadInputMethod2: function(im,old)
	{
		var j = this.im_array.length;
		
		this.im_array[j] = im;
		this.mainwin.ReplaceSelectOption(old,im.IMName(),j+1,GFCandidateListWindow.TYPE_AVAILABLE);
		im.ime = this;
/*		if(GownFull.instance.download_count == 1) */this.mainwin.SelectOption(j+1);
		Debug.trace(0,"GownFull: Input Method \"%s\" downloaded successfully. (id=%d)",im.IMName(),j+1);
		return (j+1);
	},
	SelectInputMethod: function(i)
	{
		this.mainwin.SelectOption(i);
	},
	ToggleIME: function(show)
	{
		if(show) {
			this.mainwin.SelectOption(0);
			this.mainwin.ShowWindow(true);
			Debug.trace(1,"GownFull: ToggleIME on");
		}
		else {
			this.mainwin.SelectOption(0);
			this.mainwin.ShowWindow(false);
			this.candwin.ShowWindow(false);
			Debug.trace(1,"GownFull: ToggleIME off");
		}
	},
	GetPreedit: function() { return this.preedit; },
	ResetPreedit: function()
	{
		this.mainwin.ResetPreedit();
		this.preedit = '';
		this.candwin.ShowWindow(false);
	},
	GetPreeditLength: function()
	{
		return this.preedit.length;
	},
	SetPreeditText: function(str)
	{
		this.mainwin.SetPreeditText(str);
		this.preedit = '';
	},
	// c - number of characters delete in preedit
	// dc - number of characters delete in display preedit
	DeletePreedit: function(c,dc)
	{
		var buf;

		if(dc == null) dc = 1;
		if(c == null) c = 1;

		this.mainwin.DeletePreedit(dc);
		this.preedit = this.preedit.substr(0,this.preedit.length - c);
	},
	AppendPreedit: function(c,dc)
	{
		this.mainwin.AppendPreedit(dc);
		this.preedit += c;
	},
	InvalidatePreedit: function()
	{
		this.mainwin.SetPreeditInvalid();
		this.preedit = '';
	},
	SetPreedit: function(s,ds)
	{
		this.mainwin.SetPreedit(ds);
		this.preedit = s;
	},
	SetCandidate: function(i,s) { return this.candwin.SetCandidate(i,s); },
	ShowCandidateListWindow: function(show) 
	{
		if(show) {
			this.candwin.ShowWindow(true);
			this.candwin.BringToTop();
		}
		else return this.candwin.ShowWindow(false);
	},
	SendString: function(o,s)
	{
		var it = this.modifiers.begin();
		var p;
		while(!it.nullp()) {
			p = it.current();
			Debug.trace(1,"GownFull: Modify \"%s\" by %s",s,p.ModifierName());
			s = p.Modify(s);
			it.next();
		}
		Debug.trace(1,"GownFull: Send string \"%s\"",s,this.handlers);
		return this.handlers ? this.handlers.SendString(o,s) : false; 
	}
},
{
	instance: null
});
